<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>Document</title>
	<style>
		#box{
			position:absolute;
			left:0;
			top:100px;
			width:100px;
			height:100px;
			background:red;
		}
	</style>
</head>
<body>
 	<button>跑</button>
 	<button>停</button>
	<div id="box"></div>
	<script>
	/*
	   - t 变化的时间
	   - b 初始值
	   - c 变化值 = 目标值 - 初始值
	   - d duration 持续时间
	*/
	(function(){
		if( !window.requestAnimationFrame) {
			var timer = null;
			requestAnimationFrame = function( callback ) {
				timer = setTimeout(callback,30);
				return timer;
			}
			cancelAnimationFrame = function() {
				clearTimeout( timer );
			}
		}
		
	})()
	   var Tween = {
			linear: function (t, b, c, d){  //匀速
				return c*t/d + b;
			},
			easeIn: function(t, b, c, d){  //加速曲线
				return c*(t/=d)*t + b;
			},
			easeOut: function(t, b, c, d){  //减速曲线
				return -c *(t/=d)*(t-2) + b;
			},
			easeBoth: function(t, b, c, d){  //加速减速曲线
				if ((t/=d/2) < 1) {
					return c/2*t*t + b;
				}
				return -c/2 * ((--t)*(t-2) - 1) + b;
			},
			easeInStrong: function(t, b, c, d){  //加加速曲线
				return c*(t/=d)*t*t*t + b;
			},
			easeOutStrong: function(t, b, c, d){  //减减速曲线
				return -c * ((t=t/d-1)*t*t*t - 1) + b;
			},
			easeBothStrong: function(t, b, c, d){  //加加速减减速曲线
				if ((t/=d/2) < 1) {
					return c/2*t*t*t*t + b;
				}
				return -c/2 * ((t-=2)*t*t*t - 2) + b;
			},
			elasticIn: function(t, b, c, d, a, p){  //正弦衰减曲线（弹动渐入）
				if (t === 0) { 
					return b; 
				}
				if ( (t /= d) == 1 ) {
					return b+c; 
				}
				if (!p) {
					p=d*0.3; 
				}
				if (!a || a < Math.abs(c)) {
					a = c; 
					var s = p/4;
				} else {
					var s = p/(2*Math.PI) * Math.asin (c/a);
				}
				return -(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b;
			},
			elasticOut: function(t, b, c, d, a, p){    //*正弦增强曲线（弹动渐出）
				if (t === 0) {
					return b;
				}
				if ( (t /= d) == 1 ) {
					return b+c;
				}
				if (!p) {
					p=d*0.3;
				}
				if (!a || a < Math.abs(c)) {
					a = c;
					var s = p / 4;
				} else {
					var s = p/(2*Math.PI) * Math.asin (c/a);
				}
				return a*Math.pow(2,-10*t) * Math.sin( (t*d-s)*(2*Math.PI)/p ) + c + b;
			},    
			elasticBoth: function(t, b, c, d, a, p){ 
				if (t === 0) {
					return b;
				}
				if ( (t /= d/2) == 2 ) {
					return b+c;
				}
				if (!p) {
					p = d*(0.3*1.5);
				}
				if ( !a || a < Math.abs(c) ) {
					a = c; 
					var s = p/4;
				}
				else {
					var s = p/(2*Math.PI) * Math.asin (c/a);
				}
				if (t < 1) {
					return - 0.5*(a*Math.pow(2,10*(t-=1)) * 
							Math.sin( (t*d-s)*(2*Math.PI)/p )) + b;
				}
				return a*Math.pow(2,-10*(t-=1)) * 
						Math.sin( (t*d-s)*(2*Math.PI)/p )*0.5 + c + b;
			},
			backIn: function(t, b, c, d, s){     //回退加速（回退渐入）
				if (typeof s == 'undefined') {
				   s = 1.70158;
				}
				return c*(t/=d)*t*((s+1)*t - s) + b;
			},
			backOut: function(t, b, c, d, s){
				if (typeof s == 'undefined') {
					s = 1.70158;  //回缩的距离
				}
				return c*((t=t/d-1)*t*((s+1)*t + s) + 1) + b;
			}, 
			backBoth: function(t, b, c, d, s){
				if (typeof s == 'undefined') {
					s = 1.70158; 
				}
				if ((t /= d/2 ) < 1) {
					return c/2*(t*t*(((s*=(1.525))+1)*t - s)) + b;
				}
				return c/2*((t-=2)*t*(((s*=(1.525))+1)*t + s) + 2) + b;
			},
			bounceIn: function(t, b, c, d){    //弹球减振（弹球渐出）
				return c - Tween['bounceOut'](d-t, 0, c, d) + b;
			},       
			bounceOut: function(t, b, c, d){//*
				if ((t/=d) < (1/2.75)) {
					return c*(7.5625*t*t) + b;
				} else if (t < (2/2.75)) {
					return c*(7.5625*(t-=(1.5/2.75))*t + 0.75) + b;
				} else if (t < (2.5/2.75)) {
					return c*(7.5625*(t-=(2.25/2.75))*t + 0.9375) + b;
				}
				return c*(7.5625*(t-=(2.625/2.75))*t + 0.984375) + b;
			},      
			bounceBoth: function(t, b, c, d){
				if (t < d/2) {
					return Tween['bounceIn'](t*2, 0, c, d) * 0.5 + b;
				}
				return Tween['bounceOut'](t*2-d, 0, c, d) * 0.5 + c*0.5 + b;
			}
	   };
	   var box = document.querySelector('#box');
	   var btn = document.querySelectorAll('button');
	   // var t = 0
	   // var b = parseFloat( getComputedStyle(box)['left'] );
	   // var target = 600;
	   // var c = target - b;
	   // var d = 30;
	   var timer = null;
	   btn[0].onclick = function() {
	   	  mTween({
	   	  	el: box,
	   	  	attr:{
	   	  		width:300,
	   	  		height:300
	   	  	},
	   	  	target :400,
	   	  	fx:'linear',
	   	  	duration:300,
	   	  	cb : function() {
		   	  mTween( {
			   	  	el: box,
			   	  	attr:'width',
			   	  	target :200,
				   	  	duration:300,
			   	  	cb : function() {
			   	  		
			   	  	}
		   	   })
	   	  	}
	   	  });
	   }
	   btn[1].onclick = function() {
	   	  cancelAnimationFrame( timer );
	   }
	   // function move() {
	   // 	 timer = requestAnimationFrame(function () {
	   // 	 		t ++;
	   // 	 		if( t > d ) {
	   // 	 			console.log('动画结束');
	   // 	 			cancelAnimationFrame( timer );
	   // 	 		}else{
	   // 	 			var val = Tween['backOut'](t,b,c,d);
	   // 	 			box.style.left = val + 'px';
	   // 	 		    move();
	   // 	 		}
	   // 	 })
	   // }
	   /*
			{
				el:元素,
				attr : 属性
				t: ,
				b: 
				c: ,
				duration: 
			}
	   */
	   function css( el,attr,val) {
	   	  if( arguments.length > 2) {
	   	  		if( attr == 'opacity') {
	   	  			el.style[attr] = val ;
	   	  			el.style['filter'] = 'alpha(opacity='+(val*100)+')' ;
	   	  		}else{
	   	  			el.style[attr] = val + 'px';
	   	  		}
	   	  }else{
	   	  	 return parseFloat( getStyle(el)[attr] );
	   	  }
	   	  
	   }

	   function getStyle( obj ) {
	   	  return obj.currentStyle ? obj.currentStyle : document.defaultView.getComputedStyle(obj) 
	   }
	   function mTween( objJson ) {
	   		if( !objJson ) { objJson = {}}
	   		var el = objJson.el;
	   	    var cb = objJson.cb;
	   		var target = objJson.target;
	   		var attr = objJson.attr;
	   		var t = 0;
	   		var b = {}; // {width:300,height:300}
	   		var c = {}; // { width:100,height:100}
	   		var d = Math.ceil( objJson.duration / (1000 /60) );
	   		var fx = objJson.fx || 'linear';
	   		var timer = null;
	   		for( var s in attr ) {
	   			b[s] = css(el,s);
	   			c[s] = target - attr[s];
	   		}
	   		move();
	   		function move() {
	   			timer = requestAnimationFrame(function(){
	   				t++;
	   				if( t > d ) {
	   					cancelAnimationFrame(timer);
	   					cb && cb();
	   				}else{
	   					for( s in b ) {
	   						var val = Tween[fx](t,b[s],c[s],d);
	   						css( el,s,val );
	   					}
	   					
	   					move();
	   				}

	   			})
	   		}

	   }
	</script>
</body>
</html>